using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using NetProtocol.POD;
using System.Collections.Generic;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    public class MainCityEntityCtrl : MainCityControllerBase
    {
        private Transform _entityRoot;

        public MainCityPlayerAvatarEntity playerAvatarEntity { get; private set; }
        public Dictionary<int, MainCityBaseEntity> entities { get; } = new();
        /// <summary>
        /// 四叉树查询
        /// </summary>
        private QuadTree<MainCityBaseEntity> _entityQuadTree;
        private List<MainCityBaseEntity> _tempQueryEntities = new();
        private float _playerViewRefreshTimer;
        private bool _isActive;
        /// <summary>
        /// 正在死亡的实体
        /// </summary>
        private Dictionary<int, uint> _deadingEntitys = new Dictionary<int, uint>();
        /// <summary>
        /// 掉落物表现
        /// </summary>
        private List<DropItemPlay> _dropItemPlays = new();

        protected override void OnModuleGameplayInit()
        {
            ManagerCenter.Entity.EnableGroup((int)EntityPoolGroupType.MainCityEntity);
            regionCtrl.sceneCtrl.AddPreloadAfterScene(Preload);

            MsgDispatcher.AddListener(MsgEventType.QuestAdd, NotifyQuestAdd);
            MsgDispatcher.AddListener(MsgEventType.QuestRemove, NotifyQuestRemove);
            MsgDispatcher.AddListener<int>(MsgEventType.QuestStartTrack, NotifyQuestStartTrack);
            MsgDispatcher.AddListener<FormationPOD>(MsgEventType.OneFormationChanged, OnSomeFormationChanged);
        }

        protected override void OnSceneLoaded()
        {
            //设置镜头和激活交互
            regionCtrl.cameraCtrl.CharacterFllowLook(playerAvatarEntity.transform, playerAvatarEntity.transform);
            regionCtrl.gamepadCtrl.isActive = true;
            _isActive = true;

            playerAvatarEntity.SetAsDynObstacle();
        }

        private async UniTask Preload()
        {
            //创建entityRoot
            _entityRoot = new GameObject("Entitys").transform;
            //创建四叉树
            var boundsRect = regionCtrl.navigationCtrl.boundsRect;
            _entityQuadTree = new QuadTree<MainCityBaseEntity>(boundsRect);
            //创建玩家化身
            playerAvatarEntity = ClassPool<MainCityPlayerAvatarEntity>.Get();
            var bornPos = GameMathUtil.LogicPos2UnityPos(regionCtrl.sceneGameplayConfig.defaultBornPoint);
            playerAvatarEntity.Init(bornPos);
            await playerAvatarEntity.LoadAndInstantiate(_entityRoot);
            playerAvatarEntity.OnEntityBirth();
            //创建实体
            foreach (var entityConfig in regionCtrl.sceneGameplayConfig.entityConfigs)
            {
                var entity = ClassPool<MainCityNormalEntity>.Get();
                MainCityNpcData npcSaveData = null;
                regionCtrl.dynRegion.regionSaveData?.npcs?.TryGetValue(entityConfig.id, out npcSaveData);
                entity.Init(new DynMainCityEntity(entityConfig, npcSaveData));
                entity.InitModelBase(_entityRoot);
                entities.Add(entity.id, entity);

                if (entity.dynNormalEntity.isActive)
                {
                    OnEntityActive(entity);
                }
            }
            //立即刷新视野，加载视野内实体的模型
            _playerViewRefreshTimer += MainCityConst.PlayerViewRefreshInterval;
        }

        /// <summary>
        /// 实体出生，注意进入可视区域重载模型不算
        /// </summary>
        /// <param name="entity"></param>
        private void OnEntityActive(MainCityNormalEntity entity)
        {
            if (_deadingEntitys.TryGetValue(entity.id, out var timeId))
            {
                // 如果上次死亡动画还没播完,瞬间完成
                _deadingEntitys.Remove(entity.id);
                timeId.StopTimer(true);
            }
            AddIntoQuadTree(entity);
        }

        /// <summary>
        /// 实体位置发生变化
        /// </summary>
        /// <param name="entity"></param>
        private void OnEntityPosChanged(MainCityNormalEntity entity)
        {
            UpdateQuadTree(entity);
        }

        /// <summary>
        /// 实体死亡，注意离开可视区域卸载模型不算
        /// </summary>
        /// <param name="entity"></param>
        private void OnEntityDeactive(MainCityNormalEntity entity)
        {
            RemoveFromQuadTree(entity);
        }

        private void AddIntoQuadTree(MainCityBaseEntity entity)
        {
            //添加到四叉树
            var pos = entity.unityPosOfData;
            var v2 = new Vector2(pos.x, pos.z);
            entity.quadTreePos = v2;
            _entityQuadTree.Insert(entity);
        }

        private void RemoveFromQuadTree(MainCityBaseEntity entity)
        {
            _entityQuadTree.Remove(entity);
        }

        private void UpdateQuadTree(MainCityBaseEntity entity)
        {
            var pos = entity.unityPosOfData;
            var v2 = new Vector2(pos.x, pos.z);
            _entityQuadTree.Update(entity, v2);
        }

        /// <summary>
        /// 更新数据后刷新实体显示
        /// </summary>
        /// <param name="regionCid"></param>
        /// <param name="entityMcid"></param>
        public void UpdateEntity(int regionCid, int entityMcid)
        {
            if (regionCid != this.regionCtrl.cfgRegion.Id)
            {
                return;
            }
            var npcs = regionCtrl.dynRegion.regionSaveData?.npcs;
            if (npcs == null)
            {
                LogGame.LogError("数据错误");
                return;
            }
            if (!npcs.TryGetValue(entityMcid, out var npcSaveData))
            {
                LogGame.LogError("数据错误");
                return;
            }
            if (!entities.TryGetValue(entityMcid, out var e) || e is not MainCityNormalEntity entity)
            {
                //主城不销毁实体数据，不应该找不到
                LogGame.LogError($"找不到实体数据 id: {entityMcid}");
                return;
            }

            var prevActive = entity.dynNormalEntity.isActive;
            entity.dynNormalEntity.UpdateFromServerData(npcSaveData, out var isPos2DChanged, out _);

            //先处理实体出生死亡
            if (prevActive && !npcSaveData.active)
            {
                KillEntity(entity).Forget();
            }
            else if (!prevActive && npcSaveData.active)
            {
                OnEntityActive(entity);
            }
            //刷新位置
            if (isPos2DChanged)
            {
                OnEntityPosChanged(entity);
                var moveComponent = entity.GetComponent<MainCityMoveComponent>(ETComponentType.EntityMove);
                moveComponent?.StopAndSetPosition(entity.unityPosOfData);
            }
        }

        private async UniTask KillEntity(MainCityNormalEntity entity)
        {
            entity.BroadcastComponentEvent(TComponentEvent.OnEntityObjectStartHide);

            entity.isPlayingDieAnimation = true;
            var animationComponent = entity.GetComponent<MainCityAnimationComponent>(ETComponentType.EntityAnimation);
            if (animationComponent != null && animationComponent.PlayDie())
            {
                float time = 2.5f;
                if (entity.dynNormalEntity.cfgEntity.DieDuration > 0)
                {
                    time = entity.dynNormalEntity.cfgEntity.DieDuration.MillisecToSec();
                }
                // 如果有死亡动画，等待死亡动画播放完毕
                var timerId = TimerManager.Instance.StartOneTimer(time);
                _deadingEntitys.Add(entity.id, timerId);
                await timerId.AwaitTimer();
                _deadingEntitys.Remove(entity.id);
            }
            entity.isPlayingDieAnimation = false;
            OnEntityDeactive(entity);
        }

        public void ChangePlayerViewRange(float value)
        {
            playerAvatarEntity.SetViewRange(value);
            //立即刷新视野
            _playerViewRefreshTimer += MainCityConst.PlayerViewRefreshInterval;
        }

        protected override void OnUpdate(float deltaTime)
        {
            if (!_isActive)
            {
                return;
            }
            playerAvatarEntity?.OnUpdate(deltaTime);
            foreach (var e in entities.Values)
            {
                e.OnUpdate(deltaTime);
            }
            RefreshPlayerView(deltaTime);
            UpdateDropItems(deltaTime);
        }

        /// <summary>
        /// 按玩家化身视野刷新
        /// </summary>
        private void RefreshPlayerView(float delatTime)
        {
            var p = playerAvatarEntity;
            if (p == null)
            {
                return;
            }
            _playerViewRefreshTimer += delatTime;
            if (_playerViewRefreshTimer < MainCityConst.PlayerViewRefreshInterval)
            {
                return;
            }
            _playerViewRefreshTimer = 0;
            //只能使用显示位置，因为战斗时会把角色移到很远的地方来让npc模型消失，避免消耗
            //战斗结束后会重新拉回来，但是显然这只是一个骚操作，不能动到实际数据
            //所以为了让这种操作生效，要使用显示位置来判断，这么做也并不会有隐患，因为相机是跟着显示位置走的
            //一旦相机位置变了，就应该刷新实体的模型显示
            //var playerPos = p.unityPosOfData;
            var playerPos = p.transform.position;
            float pViewRange = p.GetViewRange();
            float deleteRange = pViewRange * MainCityConst.PlayerViewRemoveRadiusRatio;
            var trackingQuestCfg = GameDataCenter.PlayerData.quest.trackQuestCfg;
            //从可视列表中删除超出了范围的实体，注意删除的范围比添加范围更大，避免玩家反复横跳
            foreach (var entity in p.entitiesInSight)
            {
                if (!entity.dynNormalEntity.isActive && !entity.isPlayingDieAnimation)
                {
                    _tempQueryEntities.Add(entity);
                    continue;
                }
                float sqrDistance = (playerPos - entity.unityPosOfData).sqrMagnitude;
                if (sqrDistance >= deleteRange * deleteRange)
                {
                    _tempQueryEntities.Add(entity);
                }
            }
            for (int i = 0; i < _tempQueryEntities.Count; i++)
            {
                var entity = _tempQueryEntities[i];
                if (p.entitiesInSight.Remove((MainCityNormalEntity)entity))
                {
                    entity.OnOutofPlayersView();
                }
            }
            _tempQueryEntities.Clear();

            //把新进入视野范围的实体添加进列表
            float halfSize = pViewRange;
            float searchSize = halfSize * 2;
            Rect searchRect = new Rect(playerPos.x - halfSize, playerPos.z - halfSize, searchSize, searchSize);
            QTQueryObjects(_tempQueryEntities, searchRect);
            //过滤视野范围内的所有实体
            foreach (var e in _tempQueryEntities)
            {
                var entity = (MainCityNormalEntity)e;
                if (!entity.dynNormalEntity.isActive && !entity.isPlayingDieAnimation)
                {
                    continue;
                }
                float sqrDistance = (playerPos - entity.unityPosOfData).sqrMagnitude;
                //进入了视野范围，需添加到列表中。
                if (sqrDistance < pViewRange * pViewRange)
                {
                    if (p.entitiesInSight.Add(entity))
                    {
                        entity.OnEnterPlayersView();
                    }
                }
            }
            _tempQueryEntities.Clear();
        }

        /// <summary>
        /// 显示掉落物表现
        /// </summary>
        /// <param name="srcEntityId"></param>
        /// <param name="items"></param>
        /// <returns></returns>
        public async UniTask ShowEntityDrop(int srcEntityId, List<ItemShowPOD> items)
        {
            if (entities.TryGetValue(srcEntityId, out var entity))
            {
                //确定掉落物随机位置（以实体为圆心的圆圈内）
                var bindCom = entity.GetComponent<EntityBindPointComponent>(ETComponentType.EntityBindPoint);
                var effectStartPos = bindCom.GetBindPoint(EntityBindPointCommonType.Middle).position;
                List<Vector3> landPoints = ListPool<Vector3>.Get();
                List<UniTask> tasks = ListPool<UniTask>.Get();
                GameScenePlayUtil.GetRandomPointInCircleOnGround(effectStartPos, GameGlobalConst.SceneDropRandomRadius, items.Count, landPoints);
                //创建所有掉落的展示对象
                for (int i = 0; i < items.Count; i++)
                {
                    var itemPOD = items[i];
                    var dropItemPlay = ClassPool<MainCityDropItemPlay>.Get();
                    //加入帧刷队列
                    //掉落表现是基于帧刷的，没有使用tween
                    _dropItemPlays.Add(dropItemPlay);
                    //创建动画任务
                    tasks.Add(dropItemPlay.Show(itemPOD.cid, itemPOD.num, effectStartPos, landPoints[i]));
                }
                //掉落物空间内部帧刷会修改任务完成情况
                //等待所有展示动画播放完毕
                await UniTask.WhenAll(tasks);
                ListPool<UniTask>.Put(tasks);
                ListPool<Vector3>.Put(landPoints);
            }
        }

        /// <summary>
        /// 刷新掉落物表现
        /// </summary>
        /// <param name="deltaTime"></param>
        private void UpdateDropItems(float deltaTime)
        {
            if (_dropItemPlays.Count > 0)
            {
                for (int i = _dropItemPlays.Count - 1; i >= 0; i--)
                {
                    var item = _dropItemPlays[i];
                    item.Update(deltaTime);
                    if (item.isExpired)
                    {
                        item.Release();
                        _dropItemPlays.RemoveAt(i);
                    }
                }
            }
        }

        /// <summary>
        /// 根据id获取实体
        /// </summary>
        /// <param name="mcid"></param>
        /// <returns></returns>
        public MainCityBaseEntity GetEntityById(int id)
        {
            if (entities.TryGetValue(id, out var entity))
            {
                return entity;
            }
            return null;
        }

        /// <summary>
        /// 根据mcid获取实体
        /// 注意目前主城的实体id和mcid是一样的，所以是在entities里取值，如果后面改了这里也要改
        /// </summary>
        /// <param name="mcid"></param>
        /// <returns></returns>
        public MainCityBaseEntity GetEntityByMcid(int mcid)
        {
            return GetEntityById(mcid);
        }

        /// <summary>
        /// 使用四叉树查询实体
        /// </summary>
        /// <param name="returnObjects"></param>
        /// <param name="area"></param>
        public void QTQueryObjects(List<MainCityBaseEntity> returnObjects, Vector3 centerPos, float range = MainCityConst.HeroQuadQueryHalfSize)
        {
            var area = GameMathUtil.GetRectRangeV2(centerPos, range);
            QTQueryObjects(returnObjects, area);
        }

        /// <summary>
        /// 使用四叉树查询实体
        /// </summary>
        /// <param name="returnObjects"></param>
        /// <param name="area"></param>
        public void QTQueryObjects(List<MainCityBaseEntity> returnObjects, Rect area)
        {
            _entityQuadTree.RetrieveObjects(returnObjects, area);
        }

        private void NotifyQuestAdd()
        {
            foreach (var entity in entities.Values)
            {
                entity.RefreshQuestState();
            }
        }

        private void NotifyQuestRemove()
        {
            foreach (var entity in entities.Values)
            {
                entity.RefreshQuestState();
            }
        }

        private void NotifyQuestStartTrack(int cid)
        {
            GameScenePlayUtil.ShowEntityTrack().Forget();
        }

        private void OnSomeFormationChanged(FormationPOD formationPOD)
        {
            playerAvatarEntity?.RefreshAvatarModel().Forget();
        }

        protected override void OnDispose()
        {
            MsgDispatcher.RemoveListener(MsgEventType.QuestAdd, NotifyQuestAdd);
            MsgDispatcher.RemoveListener(MsgEventType.QuestRemove, NotifyQuestRemove);
            MsgDispatcher.RemoveListener<int>(MsgEventType.QuestStartTrack, NotifyQuestStartTrack);

            if (_deadingEntitys.Count > 0)
            {
                // 如果有正在死亡的实体，直接完成死亡计时器
                List<uint> deading = ListPool<uint>.Get();
                deading.AddRangValue(_deadingEntitys);
                for (var i = 0; i < deading.Count; i++)
                {
                    // 直接完成死亡计时器
                    deading[i].StopTimer(true);
                }
                ListPool<uint>.Put(deading);
                _deadingEntitys.Clear();
            }

            _entityQuadTree = null;
            playerAvatarEntity?.Free();
            playerAvatarEntity = null;
            _tempQueryEntities.Clear();

            foreach (var kv in entities)
            {
                kv.Value.Free();
            }
            entities.Clear();

            ManagerCenter.Entity.DisableGroup((int)EntityPoolGroupType.MainCityEntity);
        }
    }
}
